在contextlib.py,我看到ExitStack类正在呼叫__enter__()
经由类型的对象方法(type(cm)
),而不是直接方法调用给定对象(cm
).
我想知道为什么或为什么不.
例如,
发生错误时它会提供更好的异常跟踪吗?
它只是特定于一些模块作者的编码风格?
它有任何性能优势吗?
它是否避免了复杂类型层次结构的一些工件/副作用?
Andrea Corbe.. 14
首先,当你这样做时会发生这种情况with something
,这不仅仅是contextlib
在类型上查找特殊方法.此外,值得注意的是,其他特殊方法也是如此:例如,a + b
结果type(a).__add__(a, b)
.
但为什么会这样呢?这是一个经常在python-dev和python-ideas邮件列表上启动的问题.当我说"经常"时,我的意思是"经常".
最后一个是这些:缺少核心功能:+ - */| &不要调用getattr和消除特殊方法查找.
以下是一些有趣的观点:
当前的行为是设计的 - 特殊方法被查找为对象类的插槽,而不是实例属性.这允许解释器绕过正常实例属性查找过程中的几个步骤.
(资源)
值得注意的是,这种行为比这更神奇.即使查看类,隐式特殊方法查找绕过
__getattr__
和__getattribute__
元类.因此,特殊方法查找不仅仅是在类而不是实例上启动的普通查找; 它是一个完全神奇的查找,不会在任何级别上使用通常的属性访问自定义挂钩.(资源)
此行为也记录在参考文档中:特殊方法查找,其中说:
__getattribute__()
以这种方式绕过机器为解释器内的速度优化提供了很大的空间,代价是处理特殊方法的一些灵活性(必须在类对象本身上设置特殊方法以便由解释器一致地调用) .
简而言之,性能是主要关注点.但是让我们仔细看看这个.
type(obj).__enter__()
和之间有什么区别obj.__enter__()
?
当你写作时obj.attr
,type(obj).__getattribute__('attr')
会被召唤.__getattribute__()
查找attr
实例字典(即obj.__dict__
)和类命名空间的默认实现,如果失败,则调用type(obj).__getattr__('attr')
.
现在,这是一个快速的解释,我省略了一些细节,但它应该让你知道属性查找有多复杂,以及它变得多慢.短路特殊方法查找确实提供了性能改进,因为obj.__enter__()
以"经典"方式查找可能太慢.
首先,当你这样做时会发生这种情况with something
,这不仅仅是contextlib
在类型上查找特殊方法.此外,值得注意的是,其他特殊方法也是如此:例如,a + b
结果type(a).__add__(a, b)
.
但为什么会这样呢?这是一个经常在python-dev和python-ideas邮件列表上启动的问题.当我说"经常"时,我的意思是"经常".
最后一个是这些:缺少核心功能:+ - */| &不要调用getattr和消除特殊方法查找.
以下是一些有趣的观点:
当前的行为是设计的 - 特殊方法被查找为对象类的插槽,而不是实例属性.这允许解释器绕过正常实例属性查找过程中的几个步骤.
(资源)
值得注意的是,这种行为比这更神奇.即使查看类,隐式特殊方法查找绕过
__getattr__
和__getattribute__
元类.因此,特殊方法查找不仅仅是在类而不是实例上启动的普通查找; 它是一个完全神奇的查找,不会在任何级别上使用通常的属性访问自定义挂钩.(资源)
此行为也记录在参考文档中:特殊方法查找,其中说:
__getattribute__()
以这种方式绕过机器为解释器内的速度优化提供了很大的空间,代价是处理特殊方法的一些灵活性(必须在类对象本身上设置特殊方法以便由解释器一致地调用) .
简而言之,性能是主要关注点.但是让我们仔细看看这个.
type(obj).__enter__()
和之间有什么区别obj.__enter__()
?
当你写作时obj.attr
,type(obj).__getattribute__('attr')
会被召唤.__getattribute__()
查找attr
实例字典(即obj.__dict__
)和类命名空间的默认实现,如果失败,则调用type(obj).__getattr__('attr')
.
现在,这是一个快速的解释,我省略了一些细节,但它应该让你知道属性查找有多复杂,以及它变得多慢.短路特殊方法查找确实提供了性能改进,因为obj.__enter__()
以"经典"方式查找可能太慢.